import state from './state.js';

class ProtocolManager {
    constructor() {
        this.state = state;
    }

    /**
     * 写入二进制数据到BLE特征值
     * @param {ArrayBuffer} value - 要写入的二进制数据
     * @param {Function} callback - 写入完成后的回调函数
     */
    WriteBase(value, callback) {
        const { deviceId, serviceId, characteristicId,state } = getApp().globalData.bleObj;
        if(!state){
            console.log('蓝牙未连接');
            return;
        }
        uni.writeBLECharacteristicValue({
            deviceId,
            serviceId,
            characteristicId,
            value,
            success: (res) => {
                if (res.errCode === 0 || res.errno === 0) {
                    callback?.(res);
                } else {
                    console.error('写入二进制失败', res);
                }
            },
            fail: (res) => {
                console.error('写入二进制失败', res);
            }
        });
    }

    /**
     * CRC16 Modbus 计算
     * @param {string} str - 十六进制字符串
     * @returns {string} CRC16 校验码
     */
    crc16Modbus(str) {
        const typedArray = new Uint8Array(str.trim().match(/[\da-f]{2}/gi).map(h => parseInt(h, 16)));
        let crc = 0xFFFF;
        for (const byte of typedArray) {
            crc ^= byte;
            for (let j = 0; j < 8; j++) {
                crc = (crc & 0x0001) ? (crc >>> 1) ^ 0xA001 : crc >>> 1;
            }
        }
        const lowByte = (crc & 0xFF).toString(16).padStart(2, '0');
        const highByte = ((crc >> 8) & 0xFF).toString(16).padStart(2, '0');
        return `${lowByte}${highByte}`.toUpperCase();
    }

    /**
     * 发送指令，不加2字节校验位
     * @param {string} cmd - 指令字符串
     * @param {Function} callback - 发送完成后的回调函数
     */
    sendCommand(cmd, callback) {
        cmd = cmd.trim();
        const times = Math.ceil(cmd.length / 16);
        for (let i = 0; i < times; i++) {
            const sendCmd = cmd.length > 16 ? cmd.substr(0, 16) : cmd.substr(0, cmd.length);
            cmd = cmd.length > 16 ? cmd.substr(16, cmd.length) : '';
            const typedArray = new Uint8Array(sendCmd.match(/[\da-f]{2}/gi).map(h => parseInt(h, 16)));
            this.WriteBase(typedArray.buffer, callback);
        }
    }

    /**
     * 将 ArrayBuffer 转换为十六进制字符串
     * @param {ArrayBuffer} buffer - ArrayBuffer 对象
     * @returns {string} 十六进制字符串
     */
    ab2hex(buffer) {
        return Array.prototype.map.call(new Uint8Array(buffer), bit => ('00' + bit.toString(16)).slice(-2)).join('');
    }

    /**
     * 构建读取指令
     * @param {Object} item - 指令配置项
     * @param {number} N - 参数 N
     * @param {number} X - 参数 X
     * @returns {string} 构建后的十六进制指令字符串
     */
    buildReadCmd(item, N, X) {
        const Slave = '01';
        const fun = '03';
        let start = item.start;
        const len = item.len;
        let end = '0001';
        let cmd = Slave + fun;

        if (start === '0002') {
            end = (parseInt(N, 16)).toString(16).padStart(4, '0').toUpperCase();
        } else if (start === '2002') { // 实时电流
            start = this.calculateStart(start, N, 0);
        } else if (start === '2005') { // MOS温度
            start = this.calculateStart(start, N, X, -1);
        } else if (start === 'S005') {
            start = this.calculateStart(start, N, 0);
        } else if (start === '1005') { // 电芯温度
            start = this.calculateStart(start, N, X, 1, -2);
            end = (X - 2).toString(16).padStart(4, '0').toUpperCase();
        } else {
            start = this.calculateStart(start, N, X);
            if (len > 2) {
                end = (len / 2).toString(16).padStart(4, '0').toUpperCase();
            }
        }
        cmd = cmd + start + end;
        return cmd + this.crc16Modbus(cmd);
    }

    /**
     * 构建写入指令
     * @param {Object} item - 指令配置项
     * @param {number} N - 参数 N
     * @param {number} X - 参数 X
     * @param {string} val - 写入的值
     * @returns {string} 构建后的十六进制指令字符串
     */
    buildWriteCmd(item, N, X, val) {
        const Slave = '01';
        const fun = '10';
        let start = item.start;
        const len = item.len;
        let end = '0001';
        let cmd = Slave + fun;

        start = this.calculateStart(start, N, X);
        if (len > 2) {
            end = (len / 2).toString(16).padStart(4, '0').toUpperCase() + (len).toString(16).padStart(2, '0').toUpperCase();
        } else {
            end = end + (len).toString(16).padStart(2, '0').toUpperCase();
        }
        cmd = cmd + start + end + val;
        return cmd + this.crc16Modbus(cmd);
    }

    /**
     * 计算起始地址
     * @param {string} start - 初始起始地址
     * @param {number} N - 参数 N
     * @param {number} X - 参数 X
     * @param {number} [offsetN=0] - N 的偏移量
     * @param {number} [offsetX=0] - X 的偏移量
     * @returns {string} 计算后的起始地址
     */
    calculateStart(start, N, X, offsetN = 0, offsetX = 0) {
        let startTen = parseInt(start || '0', 16);
        startTen += parseInt(N || '0', 16) + offsetN;
        startTen += parseInt(X || '0', 16) + offsetX;
        return startTen.toString(16).padStart(4, '0').toUpperCase();
    }

    /**
     * 将数字转换为大端模式的十六进制字符串
     * @param {number} num - 数字
     * @returns {string} 十六进制字符串
     */
    bufferToHex(num) {
        const buffer = new ArrayBuffer(2);
        const view = new DataView(buffer);
        view.setUint16(0, num, false); // 大端模式
        return Array.from(new Uint8Array(buffer))
            .map(byte => byte.toString(16).padStart(2, '0'))
            .join('')
            .toUpperCase();
    }

    /**
     * 解包数据
     * @param {string} str - 十六进制字符串
     * @param {Array<Object>} items - 数据项配置数组
     * @param {number} nValue - 参数 N
     * @param {number} xValue - 参数 X
     */
    solutionData(str, items, nValue, xValue) {
        let size = parseInt(str.substr(4, 2) || '0', 16);
        str = str.substr(6, size * 2);
        const xTen = parseInt(xValue || '0', 16);
        const nTen = parseInt(nValue || '0', 16);

        for (let i = 0; i < items.length; i++) {
            const item = items[i];
            let start = item.start;
            let startTen = parseInt(start || '0', 16);
            let len = item.len * 2;

            if (item.start === '0002') {
                startTen = parseInt('0002', 16);
                len = len * nTen;
            } else if (item.start === '1002') {
                startTen = parseInt('0002', 16);
            } else if (item.start === '1005') {
                startTen = parseInt('0005', 16) + 1;
                len = len * (xTen - 2);
            } else if (item.start === '2005') {
                startTen = parseInt('0005', 16) - 1;
            } else {
                startTen = this.calculateStart(start, nTen, xTen);
            }

            const val = str.substr(startTen * 4, len);
            if (item.start === '1005') {
                
            }
            item.value = this.setItemValue(val, item);
        }
    }

    /**
     * 设置数据项的值
     * @param {string} val - 十六进制字符串
     * @param {Object} item - 数据项配置
     * @returns {number|Array} 数据项的值
     */
    setItemValue(val, item) {
        const start = item.start;
        const type = item.type; // type: 0 字符串 1 数组 -1 bit数据

        if (type < 0) {
            const vArray = this.hexToBitsFast(val).split('').reverse();
            if (start === '0003') {
                return this.state.getState1(vArray.join(''));
            }
            if (start === '0004') {
                return this.state.getState2(vArray.join(''));
            }
            if (start === 'S005') { // State3
                return this.state.getState3(vArray.join(''));
            }
            if (start === '0009') { // 状态
                return this.state.getState(vArray.join(''));
            }
            if (start === '000A') { // 告警状态
                return this.state.getALARMState(vArray.join(''));
            }
            if (start === '0060') {
                return this.state.getSettingState(vArray.join(''));
            }
            return vArray;
        }

        if (type === 0) {
            let result = parseInt(val || '0', 16);
            if (['2005', '0005'].includes(start)) {
                result -= 40;
            }
            if (start === '1002') { // 当前电流
                return (result / 100).toFixed(2);
            }
            if (start === '0018') { // 电池总电压
                return (result / 100).toFixed(2);
            }
            if (['0067', '006A'].includes(start)) {
                const max = parseInt(val.substr(0, 2) || '0', 16);
                const min = parseInt(val.substr(2, 2) || '0', 16);
                return [start === '0067' ? max - 40 : max + 30, min - 40];
            }
            return result;
        }

        if (type === 1) {
            const arr = this.splitBySize(val, 4);
            const result = arr.map(t => parseInt(t, 16));
            if (start === '1005') {
                return result.map(t => t - 40);
            }
            return result;
        }

        if (type === 2) {
            const arr = this.splitBySize(val, 2);
            return arr.map(t => parseInt(t, 16));
        }

        return 0;
    }

    /**
     * 将十六进制字符串转换为二进制位字符串
     * @param {string} hexStr - 十六进制字符串
     * @returns {string} 二进制位字符串
     */
    hexToBitsFast(hexStr) {
        const hexMap = {
            '0': '0000',
            '1': '0001',
            '2': '0010',
            '3': '0011',
            '4': '0100',
            '5': '0101',
            '6': '0110',
            '7': '0111',
            '8': '1000',
            '9': '1001',
            'a': '1010',
            'b': '1011',
            'c': '1100',
            'd': '1101',
            'e': '1110',
            'f': '1111'
        };
        return hexStr.toLowerCase().split('').map(c => hexMap[c] || '0000').join('');
    }

    /**
     * 将字符串按指定大小分割
     * @param {string} str - 字符串
     * @param {number} size - 分割大小
     * @returns {Array<string>} 分割后的字符串数组
     */
    splitBySize(str, size) {
        const arr = [];
        for (let i = 0; i < str.length; i += size) {
            arr.push(str.slice(i, i + size));
        }
        return arr;
    }
}

export default new ProtocolManager();